<multiple-choice
	data-correct-label={Astro.locals.t('multipleChoice.defaultCorrect')}
	data-incorrect-label={Astro.locals.t('multipleChoice.defaultIncorrect')}
>
	<form onsubmit="event.preventDefault()">
		<ol class="opt-list not-content"><slot /></ol>
		<div class="footer">
			<button class="submit" type="submit" disabled>
				{Astro.locals.t('multipleChoice.submitLabel')}
			</button>
			<div class="answer sr-only" role="alert"></div>
		</div>
	</form>
</multiple-choice>

<style>
	multiple-choice {
		display: block;
		padding-bottom: 1rem;
		color: var(--sl-color-text-accent);
	}

	form > * + * {
		margin-top: 1rem;
	}

	.opt-list {
		list-style: none;
		padding-inline-start: 0;
	}

	.footer {
		display: grid;
		grid-template-columns: 1fr;
		gap: 1rem;
	}

	.submit,
	.answer {
		padding: 0.8rem;
		border-radius: 1.5rem;
		line-height: 1.4;
	}

	.submit {
		cursor: pointer;
		color: var(--sl-color-accent);
		background-color: white;
	}

	.submit:focus {
		background-color: hsl(224, 20%, 94%);
		outline: 3px solid var(--sl-color-accent);
		outline-offset: -3px;
	}

	.submit:not(:focus-visible) {
		outline: none;
	}

	.submit:hover {
		background: var(--sl-color-text-accent);
		color: var(--sl-color-black);
		border-color: transparent;
	}

	.submit:disabled,
	.submit:active {
		transform: translateY(0.25rem);
	}

	.submit:disabled {
		background-color: hsl(224, 20%, 94%);
		color: hsl(224, 7%, 36%);
		opacity: 0.65;
		cursor: not-allowed;
	}

	.answer {
		text-align: center;
		transition-property: color, background-color;
		transition-duration: 250ms;
		transition-timing-function: ease-out;
		border-color: transparent;
	}

	.correct {
		color: var(--sl-color-green-low);
		background-color: var(--sl-color-green);
		animation: tada 1s 0;
	}

	.wrong {
		color: var(--sl-color-red-low);
		background-color: var(--sl-color-red);
		animation: nope 0.3s 0;
	}

	@media (prefers-reduced-motion: no-preference) {
		.submit {
			transition-property: box-shadow, transform;
			transition-duration: 0.15s;
			transition-timing-function: cubic-bezier(0.4, 2.5, 0.6, 1);
		}

		.correct,
		.wrong {
			animation-iteration-count: 1;
		}
	}

	@keyframes tada {
		0%,
		100% {
			transform: scale3d(1, 1, 1);
		}
		10%,
		20% {
			transform: scale3d(0.8, 0.8, 0.8) rotate3d(0, 0, 1, -3deg);
		}
		30%,
		50%,
		70%,
		90% {
			transform: scale3d(1.05, 1.05, 1.05) rotate3d(0, 0, 1, 3deg);
		}
		40%,
		60%,
		80% {
			transform: scale3d(1.05, 1.05, 1.05) rotate3d(0, 0, 1, -3deg);
		}
	}

	@keyframes nope {
		0%,
		100% {
			transform: translate3d(0, 0, 0);
		}
		20%,
		60% {
			transform: translate3d(-0.5rem, 0, 0);
		}
		40%,
		80% {
			transform: translate3d(0.5rem, 0, 0);
		}
	}
</style>

<script>
	class MultipleChoice extends HTMLElement {
		#defaultCorrectLabel: string;
		#defaultIncorrectLabel: string;
		#key: string;
		#submitEl: HTMLButtonElement;
		#answerEl: HTMLParagraphElement;

		constructor() {
			super();
			this.#defaultCorrectLabel = this.dataset.correctLabel!;
			this.#defaultIncorrectLabel = this.dataset.incorrectLabel!;
			this.#key = Math.random().toString();
			this.#submitEl = this.querySelector('.submit')!;
			this.#answerEl = this.querySelector('.answer')!;
			this.querySelectorAll('.opt-list > li').forEach((li) => this.#upgradeListItem(li));
		}

		#upgradeListItem(li: Element) {
			const option = li.querySelector('input[type="radio"]') as HTMLInputElement | null;
			if (!option) return;

			option.removeAttribute('disabled');
			option.setAttribute('name', this.#key);
			option.addEventListener('change', () => {
				this.#clearAnswer();
				this.#enableSubmit();
			});
			if (option.checked) this.#enableSubmit();
		}

		/** Clear the answer text and hide its container visually. */
		#clearAnswer() {
			this.#answerEl.innerText = '';
			this.#answerEl.classList.remove('wrong', 'correct');
			this.#answerEl.classList.add('sr-only');
		}

		/** Show the answer result to the user. */
		#setAnswer(isCorrect: boolean) {
			const answerTemplate = this.querySelector(
				'input:checked ~ template'
			) as HTMLTemplateElement | null;
			if (answerTemplate) {
				this.#answerEl.replaceChildren(answerTemplate.content.cloneNode(true));
			} else {
				this.#answerEl.innerText = isCorrect
					? this.#defaultCorrectLabel
					: this.#defaultIncorrectLabel;
			}
			this.#answerEl.classList.remove('sr-only', 'wrong', 'correct');
			this.#answerEl.classList.add(isCorrect ? 'correct' : 'wrong');
		}

		/** Activate the submit button, preparing it to evaluate the form when clicked. */
		#enableSubmit() {
			this.#submitEl.removeAttribute('disabled');
			this.#submitEl.classList.remove('sr-only');
			this.#submitEl.onclick = () => this.#submitAnswer();
		}

		/** Disable the submit button and hide it visually. */
		#disableSubmit() {
			this.#submitEl.setAttribute('disabled', '');
			this.#submitEl.classList.add('sr-only');
			this.#submitEl.onclick = null;
		}

		/** Check if the selected option is correct and display the result. */
		#submitAnswer() {
			const selection = this.querySelector('input:checked') as HTMLInputElement | null;
			if (!selection) return;

			this.#disableSubmit();
			const isCorrect =
				selection.dataset.isCorrect !== undefined &&
				['', 'true'].includes(selection.dataset.isCorrect);
			this.#setAnswer(isCorrect);
		}
	}

	customElements.define('multiple-choice', MultipleChoice);
</script>
